package demo.security;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.springframework.boot.autoconfigure.condition.ConditionMessage;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.AccessTokenConverter;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;

import demo.security.MemoryTokenStoreConfiguration.MemoryTokenStoreCondition;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Configuration
@Conditional(MemoryTokenStoreCondition.class)
public class MemoryTokenStoreConfiguration {
		
	@Bean("MyTokenStore")	
	public TokenStore tokenStore() {
		return new InMemoryTokenStore() {

			@Override
			public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
				log.debug("***getAccessToken for principal[{}]",authentication.getName());
				return super.getAccessToken(authentication);
			}

			@Override
			public OAuth2AccessToken readAccessToken(String tokenValue) {
				log.debug("***readAccessToken({})",tokenValue);
				return super.readAccessToken(tokenValue);
			}

			@Override
			public Collection<OAuth2AccessToken> findTokensByClientIdAndUserName(String clientId, String userName) {
				log.debug("***findTokensByClientIdAndUserName({},{})",clientId,userName);
				return super.findTokensByClientIdAndUserName(clientId, userName);
			}

			@Override
			public Collection<OAuth2AccessToken> findTokensByClientId(String clientId) {
				log.debug("***findTokensByClientId({})",clientId);
				return super.findTokensByClientId(clientId);
			}
		};
	}
	
	@Bean("MyAccessTokenConverter")
	public AccessTokenConverter accessTokenConverter() {
		return new DefaultAccessTokenConverter();
	}
	
	@Bean("MyTokenEnhancer")
	public TokenEnhancer tokenEnhancer() {
	    return new TokenEnhancer(){
			@Override
			public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {				
				log.debug("***TokenEnhancer:enhance accessToken:{}",accessToken);
				
				Map<String, Object> customInfo = new HashMap();
				customInfo.put("organization", "demo-abc");
				//customInfo.put("principal", authentication.getPrincipal());
				((DefaultOAuth2AccessToken)accessToken).setAdditionalInformation(customInfo);
				return accessToken;
			}		
		};
	}	
	
	static class MemoryTokenStoreCondition extends SpringBootCondition{

		@Override
		public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {

			ConditionMessage.Builder message = ConditionMessage.forCondition("demo.tokenStore Condition");
			
			String tokenStore = context.getEnvironment().getProperty("demo.tokenStore");
			
			log.debug("*****MemoryTokenStoreCondition-tokenStore:{}", tokenStore);
			
			if(tokenStore == null || "MEMORY".equals(tokenStore)) {
				
				return ConditionOutcome.match(message.foundExactly("Memory tokenStore"));
			}
			return ConditionOutcome.noMatch(message.didNotFind("Memory tokenStore").atAll());
		}		
	}
}


